#include "parser.h"

#include <iostream>

#include "url.h"

namespace crawler { namespace server {
boost::regex PageParser::s_link_regex_(".*?(<a.*? href=(\"|')(.+?)(\"|').*?>"
                                       "(.*?)?</a>)(.*?)", boost::regex::icase);
PageParser::PageParser(const Page &page) {
  const std::string &url = page.to_url.empty() ? page.url : page.to_url;
  Url u(url);
  if (!u.IsValid()) return;

  int32_t pos = 0;
  size_t start = 0, end = 0;
  const char *page_ptr = page.content.c_str();
  while (true) {
    end = page.content.find("</a>", start);
    if (end == std::string::npos) {
      end = page.content.find("</A>", start);
    }
    if (end == std::string::npos) break;
    end += 4;
    boost::match_results<const char *> what;
    bool matched = regex_match(page_ptr + start, page_ptr + end, what, s_link_regex_);
    start = end;
    if (!matched) continue;

    Link link;
    link.__set_url(std::string(what[3].first, what[3].second));
    link.__set_anchor(std::string(what[5].first, what[5].second));
    if (link.url.empty() || link.anchor.empty()) continue;
    link.url = u.GetHrefLink(link.url);
    link.link_info = pos++;
    links_.push_back(link);
  }
}
}}

#ifdef TEST
#include <iostream>
#include <fstream>

int main(int argc, char **argv)
{
  using namespace std;
  char buffer[1024*1024];
  ifstream ifs(argv[1]);
  ifs.read(buffer, sizeof(buffer));
  buffer[ifs.gcount()] = '\0';
  struct TestPage {
    string url;
    string page;
  };
  TestPage pages[] = {
    {"http://www.example.com/a/b.html",
     "<html><head></head><body> <a id='3' href=\"/help/\" \n\n>help</a> \n"
     "<p><a class='4' href=\"home\" > home </a>> </body></html>\n"},
    {"http://www.fromweb.com/", buffer},
  };
  for (size_t i=0; i<sizeof(pages)/sizeof(pages[0]); ++i) {
    TestPage &p = pages[i];
    PageParser parser(p.url, p.page);
    vector<Link> &links = parser.GetLinks();
    for (vector<Link>::iterator it=links.begin(); it!=links.end(); ++it) {
      cout << it->url << endl;
      cout << it->anchor << endl;
      cout << it->link_info << endl;
    }
  }

  return 0;
}
}}

#endif

